package dao

import (
	"context"
	"errors"
	"ruoyi-go-echo-ddd/internal/domain/model"
	"ruoyi-go-echo-ddd/internal/infrastructure/http/request"
	"ruoyi-go-echo-ddd/internal/infrastructure/persistence/config"
	"ruoyi-go-echo-ddd/internal/infrastructure/utils"

	"github.com/rs/zerolog"
	"gorm.io/gorm"
)

type SysMenuResourcesDaoImpl struct {
	db config.PrimaryDB
}

func NewMenuResourcesDaoImpl(db config.PrimaryDB) *SysMenuResourcesDaoImpl {
	return &SysMenuResourcesDaoImpl{
		db: db,
	}
}

func (repo *SysMenuResourcesDaoImpl) Insert(ctx context.Context, sysMenuResources *model.SysMenuResources) (*model.SysMenuResources, error) {
	if err := repo.db.WithContext(ctx).Create(&sysMenuResources).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("系统菜单资源对应表新增错误")
		return nil, errors.New("系统菜单资源对应表新增失败")
	}
	// 如果这里边有使用钩子函数，那么这里需要重新查询而不是直接返回sysMenuResources
	sysMenuResources, err := repo.SelectById(ctx, sysMenuResources.Id)
	if err != nil {
		return nil, errors.New("系统菜单资源对应表新增失败")
	}
	return sysMenuResources, nil
}

func (repo *SysMenuResourcesDaoImpl) Update(ctx context.Context, sysMenuResources *model.SysMenuResources) (int64, error) {
	result := repo.db.WithContext(ctx).
		Omit("id").
		Save(&sysMenuResources)
	if result.Error != nil {
		zerolog.DefaultContextLogger.Error().Err(result.Error).Msg("系统菜单资源对应表修改错误")
		return 0, errors.New("系统菜单资源对应表修改失败")
	}

	return result.RowsAffected, nil
}

func (repo *SysMenuResourcesDaoImpl) BatchInsert(ctx context.Context, list []*model.SysMenuResources) ([]int64, error) {
	if len(list) <= 0 {
		return nil, errors.New("系统菜单资源对应表批量新增参数验证失败")
	}

	zerolog.DefaultContextLogger.Info().Msgf("系统菜单资源对应表批量新增参数===%v", list)

	result := repo.db.WithContext(ctx).CreateInBatches(list, 2000)
	if result.Error != nil {
		zerolog.DefaultContextLogger.Error().Err(result.Error).Msg("系统菜单资源对应表批量新增错误")
		return nil, errors.New("系统菜单资源对应表批量新增失败")
	}

	var ids []int64
	for _, item := range list {
		ids = append(ids, item.Id)
	}

	zerolog.DefaultContextLogger.Info().Msgf("系统菜单资源对应表批量新增成功条数===%d,返回ids:===%v", result.RowsAffected, ids)
	return ids, nil
}

func (repo *SysMenuResourcesDaoImpl) SelectById(ctx context.Context, id int64) (*model.SysMenuResources, error) {
	var sysMenuResources *model.SysMenuResources
	// 主键为id的时候First(&sysMenuResources, id)默认使用主键ID查询
	if err := repo.db.WithContext(ctx).Model(&model.SysMenuResources{}).First(&sysMenuResources, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("系统菜单资源对应表未找到")
		}
		zerolog.DefaultContextLogger.Error().Err(err).Msg("查询SysMenuResources失败")
		return nil, errors.New("系统菜单资源对应表查询失败")
	}
	return sysMenuResources, nil
}

func (repo *SysMenuResourcesDaoImpl) SelectPage(ctx context.Context, param *request.SysMenuResourcesReq) ([]*model.SysMenuResources, int64, int64, error) {
	pageParam := utils.InitPageParam(param.Page, param.Size)

	// 初始化 GORM 查询
	db := repo.db.WithContext(ctx).Model(&model.SysMenuResources{})
	// 查询总记录数
	var total int64
	if err := db.Count(&total).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("获取系统菜单资源对应表总记录数异常")
		return nil, 0, 0, errors.New("获取系统菜单资源对应表总记录数失败")
	}

	// 查询用户列表
	var list []*model.SysMenuResources
	if err := db.Offset(int(pageParam.Offset)).Limit(int(pageParam.Size)).Order("id DESC").Find(&list).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msgf("获取系统菜单资源对应表列表异常, 参数===%+v", param)
		return nil, 0, 0, errors.New("获取系统菜单资源对应表列表失败")
	}

	return list, total, utils.CalcTotalPage(total, param.Size), nil
}

func (repo *SysMenuResourcesDaoImpl) BatchDelete(ctx context.Context, ids []any) (int64, error) {
	if len(ids) <= 0 {
		return 0, errors.New("系统菜单资源对应表批量删除参数验证失败")
	}
	zerolog.DefaultContextLogger.Info().Msgf("系统菜单资源对应表批量删除参数===%v", ids)

	result := repo.db.WithContext(ctx).Model(&model.SysMenuResources{}).Where("id IN ?", ids).Delete(nil)
	if result.Error != nil {
		zerolog.DefaultContextLogger.Error().Err(result.Error).Msg("系统菜单资源对应表批量删除异常")
		return 0, errors.New("批量删除失败")
	}

	zerolog.DefaultContextLogger.Info().Msgf("系统菜单资源对应表批量删除成功执行条数===%d", result.RowsAffected)
	return result.RowsAffected, nil
}

func (repo *SysMenuResourcesDaoImpl) SelectAllForExcel(ctx context.Context) ([]*model.SysMenuResources, error) {
	var (
		list    []*model.SysMenuResources
		allData []*model.SysMenuResources
		count   int64
		page    = 1
		size    = 10000
	)
	db := repo.db.WithContext(ctx).Model(&model.SysMenuResources{})
	if err := db.Count(&count).Error; err != nil {
		zerolog.DefaultContextLogger.Error().Err(err).Msg("查询菜单资源总条数错误")
		return nil, errors.New("查询菜单资源总条数失败")
	}
	zerolog.DefaultContextLogger.Info().Msgf("获取菜单资源分页===%d,当前分页批数===%d", count, size)

	// 分页大小大于或等于总条数，则直接一次性查询
	if int64(size) >= count {
		if err := db.Find(&allData).Error; err != nil {
			return nil, err
		}
		zerolog.DefaultContextLogger.Info().Msgf("分页大小大于或等于总条数一次性查询所有数据的条数===%d", len(allData))
		return allData, nil
	}

	for {
		list = list[:0]
		if err := db.Limit(size).Offset((page - 1) * size).Find(&list).Error; err != nil {
			return nil, err
		}
		zerolog.DefaultContextLogger.Info().Msgf("第%d次查询菜单资源分页数据条数===%d", page, len(list))

		if len(list) == 0 {
			zerolog.DefaultContextLogger.Info().Msgf("第%d次查询菜单资源分页数据条数为0退出循环", page)
			break
		}
		allData = append(allData, list...)
		page++
	}
	return allData, nil
}
